using UniversalAdminSystem.Domian.PermissionManagement.Services;
using UniversalAdminSystem.Domian.PermissionManagement.ValueObjects;
using UniversalAdminSystem.Domian.Core;
using UniversalAdminSystem.Domian.Core.Events;
using UniversalAdminSystem.Domian.Core.ValueObjects;

namespace UniversalAdminSystem.Domian.PermissionManagement.Aggregate;

/// <summary>
/// 权限实体，一个具体的权限项
/// </summary>
public class Permission : AggregateRoot
{
    /// <summary>
    /// 唯一标识
    /// </summary>
    public Guid PermissionId { get; private set; }

    /// <summary>
    /// 权限编码（不能为空，不变性）：提供机器可读的权限标识，用于程序中的权限检查
    /// </summary>
    public PermissionCode Code { get; private init; } = null!;

    /// <summary>
    /// 权限名称（不能为空）
    /// </summary>
    public PermissionName Name { get; private set; } = null!;

    /// <summary>
    /// 描述：提供人类可读的权限描述，用于界面展示
    /// </summary>
    public string? Description { get; private set; }

    /// <summary>
    /// 类型：分类权限，便于管理和使用
    /// </summary>
    public PermissionType PermissionType { get; private set; }

    /// <summary>
    /// 作用资源：指明该权限控制的是哪个资源
    /// </summary>
    public PermissionResource Resource { get; private set; } = null!;

    /// <summary>
    /// 操作类型：指明对资源的具体操作
    /// </summary>
    public PermissionAction Action { get; private set; }

    /// <summary>
    /// 是否为系统权限（默认为false）：系统权限不可删除，不可修改
    /// </summary>
    public bool IsSystem { get; private set; } = false;

    /// <summary>
    /// 创建时间：创建权限时的当前事件，不可修改
    /// </summary>
    public DateTime CreateTime { get; private set; } = DateTime.UtcNow;

    /// <summary>
    /// 更新时间：更新权限时的当前时间，每次更新权限时都会更新
    /// </summary>
    public DateTime UpdateTime { get; private set; } = DateTime.UtcNow;


    /// <summary>
    /// 无参构造函数，供EFCore使用
    /// </summary>
    private Permission() { }

    /// <summary>
    /// 私有构造函数供工厂使用
    /// </summary>
    /// <param name="name"></param>
    /// <param name="permissionType"></param>
    private Permission(
        Guid permissionId,
        PermissionCode code,
        PermissionName name,
        string? description,
        PermissionType permissionType,
        PermissionResource resource,
        PermissionAction action,
        bool isSystem,
        DateTime createTime,
        DateTime updateTime
    )
    {
        PermissionId = permissionId;
        Code = code;
        Name = name;
        Description = description;
        PermissionType = permissionType;
        Resource = resource;
        Action = action;
        IsSystem = isSystem;
        CreateTime = createTime;
        UpdateTime = updateTime;
    }

    /// <summary>
    /// 根据权限作用资源获取权限类型
    /// </summary>
    /// <param name="resource"></param>
    /// <returns></returns>
    private static PermissionType GetTypeByResource(string resource)
    {
        return resource switch
        {
            string r when r.StartsWith("data.", StringComparison.OrdinalIgnoreCase) => PermissionType.DATA,
            string r when r.StartsWith("user.", StringComparison.OrdinalIgnoreCase) => PermissionType.USER,
            string r when r.StartsWith("file.", StringComparison.OrdinalIgnoreCase) => PermissionType.FILE,
            string r when r.StartsWith("enum.", StringComparison.OrdinalIgnoreCase) => PermissionType.ENUN,
            string r when r.StartsWith("system.", StringComparison.OrdinalIgnoreCase) => PermissionType.SYSTEM,
            _ => PermissionType.OTHER,
        };
    }

    /// <summary>
    /// 创建标准权限的工厂方法
    /// </summary>
    /// <param name="code"></param>
    /// <param name="name"></param>
    /// <param name="description"></param>
    /// <param name="permissionType"></param>
    /// <returns></returns>
    public static Permission CreateStandardPermission(
        string name,
        string resource,
        int actionValue,
        string? description = null
    )
    {
        // 校验数据完整性
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException("权限名称不能为空", nameof(name));
        if (string.IsNullOrWhiteSpace(resource))
            throw new ArgumentException("作用资源不能为空", nameof(resource));
        if (!Enum.IsDefined(typeof(PermissionAction), actionValue))
            throw new ArgumentException("无效的操作类型值", nameof(actionValue));

        if (!ResourceActionValidator.IsValidCombination(resource, actionValue, out var permResource, out var permAction))
            throw new ArgumentException("资源与操作类型组合不合法");
        
        // 显示转换类型，内部校验格式
        PermissionCode permCode = (PermissionCode)$"{resource}:{permAction}";
        PermissionName permName = (PermissionName)name;
        PermissionType permType = GetTypeByResource(resource);

        // 创建标准权限
        var permission = new Permission(
            Guid.NewGuid(),
            permCode,
            permName,
            string.IsNullOrWhiteSpace(description) ? "暂无描述" : description,
            permType,
            permResource,
            permAction,
            false,
            DateTime.UtcNow,
            DateTime.UtcNow
        );
        
        return permission;
    }

    /// <summary>
    /// 创建系统权限的工厂方法
    /// </summary>
    /// <param name="code"></param>
    /// <param name="name"></param>
    /// <param name="description"></param>
    /// <param name="permissionType"></param>
    /// <returns></returns>
    public static Permission CreateSystemPermission(
        string name,
        string resource,
        int actionValue,
        string? description = null
    )
    {
        var perm = CreateStandardPermission(name, resource, actionValue, description);
        perm.IsSystem = true;
        return perm;
    }

    /// <summary>
    /// 修改权限名称
    /// </summary>
    /// <param name="name"></param>
    /// <exception cref="ArgumentException"></exception>
    public void UpdateName(string name)
    {
        Name = PermissionName.Create(name);
        UpdateTime = DateTime.Now;
    }

    /// <summary>
    /// 修改权限描述
    /// </summary>
    /// <param name="description"></param>
    /// <exception cref="ArgumentException"></exception>
    public void UpdateDescription(string? description = null)
    {
        // 允许传入null表示清空权限描述 
        if (string.IsNullOrWhiteSpace(description))
        {
            Description = "暂无描述";
            return;
        }

        // 参数非null才进行规则校验
        if (description.Length > 50)
        {
            throw new ArgumentException("权限描述长度不能超过50字符", nameof(description));
        }

        Description = description;
        UpdateTime = DateTime.Now;
    }
}